Backward Compatibility Fix for run_provider.py Refactoring
Date: 2025-11-03 Status: ✅ COMPLETE Priority: 🔴 CRITICAL Issue: User unable to run EPG generation after Task 2.2 refactoring
Problem Summary
After completing Sprint 2 Task 2.2 (refactoring backend/epgoat/cli/run_provider.py), the user encountered a critical error when attempting to run EPG generation:
ERROR: Missing required parameters: m3u and out_xmltv (provide via CLI, ENV, or YAML)
This occurred even when providing both parameters via CLI flags, indicating a fundamental incompatibility between the refactored code and existing provider configurations.
Root Cause
The refactored backend/epgoat/data/config_loader.py module expected a YAML config structure that never existed:
Expected (Refactored Code):
input:
type: url
m3u_url: https://...
output:
epg_xml: dist/provider.xml
audit_csv: dist/provider_audit.csv
Actual (All Existing Configs):
provider:
m3u_url: https://...
# No output paths defined
Impact
- ❌ User completely unable to run EPG generation
- ❌ All provider configs incompatible with refactored code
- ❌ Critical production blocker
Solution
Updated backend/epgoat/data/config_loader.py to support both config structures with proper fallback logic:
1. M3U Input Resolution (resolve_m3u_input)
Added fallback chain:
1. CLI override (highest priority)
2. New structure: input.m3u_url
3. Legacy structure: provider.m3u_url ← NEW FALLBACK
# Fallback: Try old structure (provider.m3u_url)
url = self.get_config_value(config, "provider.m3u_url")
if url:
url = self.expand_env_vars(url)
return url
2. Output Path Resolution (build_epg_args)
Added triple fallback for outputs:
1. CLI args (highest priority)
2. Config values (output.epg_xml, output.audit_csv)
3. Sensible defaults: dist/{provider}.xml, dist/{provider}_audit.csv ← NEW
out_xmltv = (
cli_args.out_xmltv
or self.get_config_value(config, "output.epg_xml")
or f"dist/{provider_slug}.xml" # Sensible default
)
3. M3U Config Fallback in build_epg_args
Added provider.m3u_url fallback:
m3u = (
cli_args.m3u
or self.get_config_value(config, "input.m3u_url")
or self.get_config_value(config, "provider.m3u_url") # Fallback
)
Testing
Added 4 New Tests
test_resolve_m3u_input_legacy_provider_structure-
Verifies
provider.m3u_urlfallback works -
test_build_epg_args_legacy_provider_structure - Full integration test with legacy config structure
-
Verifies both M3U and output path fallbacks
-
test_build_epg_args_default_output_paths -
Verifies sensible defaults (
dist/{provider}.xml) -
test_build_epg_args_new_structure_takes_precedence - Ensures new structure has priority over legacy
Test Results
28 passed in 0.03s ✅
All existing tests still pass + 4 new backward compatibility tests.
Manual Verification
Command:
python3 backend/epgoat/run_provider.py \
--provider tps \
--max-channels 5 \
--m3u "https://rocketone.vip:443/get.php?username=90381950&password=66813434&type=m3u&output=ts" \
--skip-refresh \
--disable-api
Result: ✅ SUCCESS
- M3U processed: 32,252 live TV entries
- XMLTV generated: /Users/abel_flores/Documents/GitHub/epgoat-internal/dist/tps.xml
- Audit CSV written: /Users/abel_flores/Documents/GitHub/epgoat-internal/dist/tps_audit.csv
- 5 channels processed successfully
Files Modified
| File | Changes | Lines Changed |
|---|---|---|
backend/epgoat/cli/provider_runner/config_loader.py |
Added legacy fallbacks | +15 |
backend/epgoat/tests/test_provider_runner_config_loader.py |
Added 4 backward compat tests | +95 |
backend/epgoat/cli/provider_runner/task_orchestrator.py |
Fixed clone_m3u.py args + input | +10 |
Specific Changes
config_loader.py - resolve_m3u_input() (lines 110-163)
- Added
provider.m3u_urlfallback at end of method - Maintains all existing validation and environment variable expansion
config_loader.py - build_epg_args() (lines 165-247)
- Added
provider.m3u_urlto M3U fallback chain - Added sensible default:
dist/{provider}.xmlfor out_xmltv - Added sensible default:
dist/{provider}_audit.csvfor csv - Updated error message to clarify only m3u is truly required (out_xmltv has default)
Backward Compatibility Guarantees
✅ Preserved
- New config structure still works (if anyone creates it)
- CLI arguments take highest priority (unchanged)
- Legacy configs (provider.m3u_url) now work ← FIXED
- Sensible defaults provided when outputs not specified
Priority Order (M3U Input)
--m3uCLI flag (highest)input.m3u_url(config)provider.m3u_url(config, new fallback)
Priority Order (Output Paths)
--out-xmltvCLI flag (highest)output.epg_xml(config)dist/{provider}.xml(sensible default, new)
Risk Assessment
Pre-Fix
- Risk Level: 🔴 CRITICAL
- Impact: Complete production blocker
- Affected Users: 100% (all provider configs broken)
Post-Fix
- Risk Level: 🟢 LOW
- Impact: Backward compatible, no breaking changes
- Test Coverage: 28 passing tests (4 new)
- Validation: Manual end-to-end test successful
Lessons Learned
What Went Wrong
- Assumed config structure without validating existing configs
- No migration plan for existing configs during refactoring
- Tests didn't catch config structure mismatch (tests used expected structure, not actual)
Improvements for Future Refactoring
- ✅ Check existing configs before changing structure expectations
- ✅ Always provide fallbacks when changing config structure
- ✅ Test with actual configs from production/staging
- ✅ Add backward compatibility tests for any breaking changes
- ✅ Provide sensible defaults to reduce required configuration
Additional Fixes
Issue 2: clone_m3u.py Unsupported Arguments
Error Discovered:
clone_m3u.py: error: unrecognized arguments: --prefix tps --preserve-existing
Root Cause: Refactored backend/epgoat/cli/provider_runner/task_orchestrator.py called backend/epgoat/utilities/clone_m3u.py with arguments the script doesn't support:
- Script accepts: --input, --output, [--verbose]
- Orchestrator called with: --prefix, --preserve-existing (don't exist)
Fix Applied:
1. ✅ Removed unsupported --prefix and --preserve-existing arguments
2. ✅ Added optional --verbose flag based on config
Issue 3: clone_m3u.py URL Instead of File Path
Error Discovered:
ERROR: Failed to read input M3U: [Errno 2] No such file or directory: 'https://...'
Root Cause: backend/epgoat/utilities/clone_m3u.py expects a local file path, but task_orchestrator passed the original M3U URL.
Fix Applied:
1. ✅ Use local event M3U file (dist/{provider}.m3u) created during EPG generation
2. ✅ Added existence check before attempting clone
3. ✅ Added fallback warning if local file doesn't exist
Final Test Results
Command:
python3 backend/epgoat/run_provider.py \
--provider tps \
--max-channels 5 \
--m3u "https://..." \
--skip-refresh \
--disable-api
Output: ✅ ALL FILES GENERATED SUCCESSFULLY
✓ XMLTV written: dist/tps.xml
✓ Enhanced audit CSV written: dist/tps_audit.csv
✓ Event-only M3U written: dist/tps.m3u
✓ Clone M3U written: dist/tps-clone.m3u
EPG pipeline completed successfully!
Related Documents
- Sprint 2 Week 6 Task 2.2 Plan - Original refactoring plan
- Session Status - Current project status
Last Updated: 2025-11-03 Status: ✅ Complete - All tests passing, manual verification successful Next Steps: Continue with remaining Sprint 2 tasks (Week 7)